import "./BooksTable.scss";
import {ReactComponent} from "../../class/ReactComponent";
import React, {forwardRef, Ref} from "react";
import {RouteComponentProps, StaticContext, withRouter} from "react-router";
import {TableBookList} from "../../../common/class/TableBookList";
import tableBookList from "../../../common/function/tableBookList";
import {Avatar, Button, Icon, message, Modal, Table} from "antd";
import {PaginationConfig} from "antd/es/pagination";
import {jsonCopy} from "../../../common/function/objFunc";
import {ColumnProps, TableRowSelection} from "antd/es/table";
import {openURLInExplorer} from "../../../common/function/appFunc";
import moment from "moment";
import {sortString} from "../../../common/function/stringFunc";
import {TableArticleList} from "../../../common/class/TableArticleList";

export namespace BooksTable {
    export interface Props extends ReactComponent.Props, RouteComponentProps<any, StaticContext, any> {
        onEdit?: (data: Partial<TableBookList.Data>) => void;
        filterString?: string;
        onClickAuthor?: (author: string, evt?: any) => void;
    }

    export interface State extends ReactComponent.State {
        list: TableBookList.Data[];
        filterList: TableBookList.Data[];
        pagination: false | PaginationConfig;
    }
}

export class BooksTable extends ReactComponent<BooksTable.Props, BooksTable.State> {
    public readonly state: BooksTable.State = {
        list: [],
        pagination: false,
        filterList: [],
    };
    public readonly pageSize = 4;
    private selectedRowIds: number[] = [];
    private selectedRows: TableBookList.Data[] = [];

    public render(): React.ReactElement<BooksTable.Props, string | React.JSXElementConstructor<any>> {
        return (
            <div className={this.getClsName("books-table-component")}>
                <Table
                    pagination={this.state.pagination}
                    rowSelection={this.getRowSelectionObj(this)}
                    rowKey="id"
                    columns={this.getCols()}
                    dataSource={this.state.filterList}
                />
            </div>
        );
    }

    public componentDidMount(): void {
        this.updateList();
    }

    public componentDidUpdate(
        prevProps: Readonly<BooksTable.Props>,
        prevState: Readonly<BooksTable.State>,
        snapshot?: any
    ): void {
        if (this.props.filterString !== prevProps.filterString) {
            this.updateTableRows();
        }
    }

    public showProp(record: TableBookList.Data) {
        if (typeof this.props.onEdit === "function") {
            this.props.onEdit(record);
        }
    }

    public updateList() {
        tableBookList.select().findAll()
            .then((rows: any) => {
                this.afterGetRows(rows);
            }).catch((err: Error) => {
            console.error(err);
        });
    }

    public delItem(record: TableBookList.Data) {
        this.confirmToDelItem(record)
            .then(() => {
                this.trueDelItem(record);
            }).catch(() => {
                // do nothing;
            });
    }
    public confirmToDelItem(record: TableBookList.Data) {
        return new Promise((resolve, reject) => {
            Modal.confirm({
                title: "确认删除",
                content: `确定要删除《${record.name}》吗`,
                onOk() {
                    resolve();
                },
                onCancel() {
                    reject();
                },
            });
        });
    }

    public getSelectedRowIds(): number[] {
        return this.selectedRowIds.map((item) => {
            return item;
        });
    }

    public getSelectedRows(): TableBookList.Data[] {
        return jsonCopy(this.selectedRows);
    }

    public openURL(evt: any) {
        const url = evt.target.getAttribute("title");
        if (url && url.trim()) {
            openURLInExplorer(url).then(() => {
                message.success("已在其他应用中打开");
            }).catch((err) => {
                console.error(err);
            });
        }
    }

    public deletedSelectedRows() {
        const selectedIds = this.getSelectedRowIds();
        if (selectedIds.length) {
            tableBookList.deleteByKeyList(selectedIds)
                .then(() => {
                    this.deleteArticleByBookIdList(selectedIds);
                    message.success("删除成功");
                }).catch((err) => {
                    message.error("删除失败");
                    console.error(err);
                }).finally(() => {
                    this.updateList();
                });
        }
    }
    protected deleteArticleByBookIdList(selectedIds: number[]) {
        TableArticleList.getInstance()
            .deleteByBookIdList(selectedIds)
            .then(() => {
                // do nothing;
            }).catch((err) => {
                message.error("删除章节列表出错");
            });
    }
    protected trueDelItem(record: TableBookList.Data) {
        tableBookList.where("id", record.id)
            .delete()
            .then(() => {
                this.deleteArticleByBookIdList([ record.id ]);
                message.success("删除成功");
            }).catch((err) => {
                message.error("删除失败");
                console.error(err);
            }).finally(() => {
                this.updateList();
            });
    }

    protected getCols(): Array<ColumnProps<TableBookList.Data>> {
        const context = this;
        return [
            {
                title: "书名",
                key: "name",
                dataIndex: "name",
                className: "col-name",
                sorter(itemA, itemB) {
                    return sortString(itemA.name, itemB.name);
                },
                render(bookName: string, record: TableBookList.Data) {
                    return (
                        <div
                            className="book-name clickable"
                            onClick={context.onClickBook.bind(context, record)}
                        >{bookName}</div>
                    );
                },
            },
            {
                title: "作者",
                key: "author",
                dataIndex: "author",
                className: "col-author",
                render(author: string): any {
                    return (<div
                        className="clickable"
                        onClick={context.onClickAuthor.bind(context, author)}
                    >{author}</div>);
                },
                sorter(itemA, itemB) {
                    return sortString(itemA.author, itemB.author);
                },
            },
            {
                title: "封面",
                key: "cover",
                className: "col-cover",
                dataIndex: "cover",
                render(url: string) {
                    return (<Avatar shape="square" src={url}/>);
                },
            },
            {
                title: "更新频率",
                key: "frequency",
                dataIndex: "update_frequency",
                className: "col-frequency",
                render(text: string): any {
                    switch (text) {
                        case "week":
                            return "周更";
                        case "day":
                            return "日更";
                        case "month":
                            return "月更";
                        default:
                            return "-";
                    }
                },
                sorter(itemA: TableBookList.Data, itemB: TableBookList.Data) {
                    return context.sortFrequency(itemA.update_frequency, itemB.update_frequency);
                },
            },
            {
                title: "上次更新时间",
                key: "last_update_time",
                dataIndex: "last_update_time",
                className: "col-update_time",
                render(timestamp: string): any {
                    if (timestamp) {
                        return moment(new Date(timestamp)).format("YYYY/MM/DD 周dd HH:mm:ss");
                    }
                    return timestamp;
                },
                sorter(itemA, itemB) {
                    return context.sortUpdateTime(itemA.last_update_time, itemB.last_update_time);
                },
            },
            {
                title: "更新地址",
                key: "url",
                dataIndex: "update_refer_url",
                className: "col-url",
                defaultSortOrder: "ascend",
                sortDirections: ["descend", "ascend"],
                sorter(a: TableBookList.Data, b: TableBookList.Data) {
                    return context.sortURL(a.update_refer_url, b.update_refer_url);
                },
                render(url: string): any {
                    return (<div
                        className="update-link clickable"
                        title={url}
                        onClick={context.openURL.bind(context)}
                    >{url}</div>);
                },
            },
            {
                title: "更新函数",
                key: "update_method",
                dataIndex: "update_method",
                className: "col-method",
            },
            context.getColOperator()
        ];
    }

    // protected

    protected getColOperator() {
        const context = this;
        return {
            title: "操作",
            key: "operation",
            className: "col-operation",
            render(url: string, record: TableBookList.Data): any {
                return (
                    <div>
                        <Button type="primary" title="编辑" onClick={context.showProp.bind(context, record)}>
                            <Icon type="edit"/>
                            <span className="btn-name">编辑</span>
                        </Button>
                        <Button type="danger" title="删除" onClick={context.delItem.bind(context, record)}>
                            <Icon type="delete"/>
                            <span className="btn-name">删除</span>
                        </Button>
                    </div>
                );
            },
        };
    }
    protected sortUpdateTime(itemA: number, itemB: number): number {
        if (!itemA) {
            return 1;
        }
        if (!itemB) {
            return -1;
        }
        return itemA - itemB;
    }

    protected sortFrequency(itemA: string, itemB: string): number {
        if (itemA === itemB) {
            return 1;
        }
        const list = ["day", "week", "month"];
        const itemAIndex = list.indexOf(itemA);
        const itemBIndex = list.indexOf(itemB);
        return itemAIndex - itemBIndex;
    }

    protected sortURL(urlA: string, urlB: string): number {
        return sortString(urlA, urlB);
    }

    protected afterGetRows(rows: TableBookList.Data[]) {
        this.setState({
            list: rows,
        }, () => {
            this.updateTableRows();
        });
    }

    protected updateTableRows(filterString: string = this.props.filterString) {
        const that = this;
        const rows = this.state.list;
        const filterList = that.doFilterRows(rows, filterString);
        let pagination: false | PaginationConfig = false;
        const pageSize: number = this.pageSize;
        if (filterList.length > pageSize) {
            pagination = {
                pageSize,
                current: 1,
                onChange(page: number) {
                    const pag = that.state.pagination as PaginationConfig;
                    pag.current = page;
                },
            };
        }
        this.setState({
            filterList,
            pagination,
        });
    }

    protected doFilterRows(
        rows: TableBookList.Data[],
        filterString: string = this.props.filterString
    ): TableBookList.Data[] {
        if (!filterString || !filterString.trim()) {
            return rows;
        }
        filterString = filterString.toLowerCase();
        return rows.filter((rowItem) => {
            let name = rowItem.name.toLowerCase();
            if (name.indexOf(filterString) >= 0) {
                return true;
            }
            if (rowItem.author) {
                name = rowItem.author.toLowerCase();
            }
            return name.indexOf(filterString) >= 0;
        });
    }

    protected getRowSelectionObj(context: this): TableRowSelection<TableBookList.Data> {
        return {
            onChange(selectedRowKeys: string[] | number[], rows: TableBookList.Data[]) {
                context.updateSelectedRows(selectedRowKeys, rows);
            },
        };
    }

    protected updateSelectedRows(selectedRowKeys: string[] | number[], rows: TableBookList.Data[]) {
        this.selectedRowIds = selectedRowKeys as number[];
        this.selectedRows = rows;
    }

    protected onClickAuthor(author: string) {
        if (typeof this.props.onClickAuthor === "function") {
            this.props.onClickAuthor(author, event);
        }
    }

    protected onClickBook(bookItem: TableBookList.Data) {
        this.props.history.push({
            pathname: "/operate/articles/" + bookItem.id,
        });
    }
}

export const BooksTableWithRouter = withRouter<BooksTable.Props, any>(BooksTable);
